/* ----------------------------------------------------------------------
 *	Shadow Quest
 *	Copyright (C) 2009 Prageeth Silva <prageeth@thenewcoders.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *  ----------------------------------------------------------------------
 */
package menu;

import java.util.ArrayList;

import menu.MenuButton.ButtonType;

import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

import sq.ImageLoader;
import sq.RPG;
import sq.FontLoader;

/** A submenu for use in Menus
 * 
 */
public class SubMenu {

    private static String ESCAPE = "Press ESCAPE to return to the Main Menu";
    private static int TITLE_TOP = 35, ESCAPE_TOP = 20;
    private String title;
    private Menu menu;
    private Animation disp;
    private boolean showing, opening, closing;
    private ArrayList<MenuTab> tabs;
    private ArrayList<MenuButton> buttons;
    private boolean click;
    private MenuButton.ButtonType menuState;
    private int currentTab;
    private boolean showingCancelOK;

    /** Create a new SubMenu object
     * @param menu The Menu in which the submenu exists
     * @param tabs A list of tabs in the submenu
     * @param title The title of the submenu
     * @param OKCancelButtons If the OK and Cancel buttons should be displayed and active
     */
    public SubMenu(Menu menu, ArrayList<MenuTab> tabs, String title, boolean OKCancelButtons)
            throws SlickException {

        this.setMenu(menu);
        this.setCurrentTab(0);
        this.setMenuState(MenuButton.ButtonType.NONE);
        this.setClick(false);
        this.setOpening(false);
        this.setClosing(false);
        this.setTitle(title);
        this.setTabs(tabs);
        this.setShowingCancelOK(false);
        this.setDisplayAnimation(ImageLoader.getSubMenuOpen());
        this.setShowingCancelOK(OKCancelButtons);
        this.setButtons(new ArrayList<MenuButton>());
        this.loadDefaultButtons();
        this.loadButtons();

    }

    private void loadDefaultButtons()
            throws SlickException {

        String dirPath = "assets/menu/submenu/", hover = "hover_", file = "left_arrow.png";

        Image nor = ImageLoader.getLoadedImage(dirPath + file);
        Image hov = ImageLoader.getLoadedImage(dirPath + hover + file);

        // initalise the buttons
        MenuButton b = new MenuButton(nor, hov, 36, 486, ButtonType.BACK);
        b.setShown(false);
        this.getButtons().add(b);
        b = new MenuButton(nor.getFlippedCopy(true, false), hov.getFlippedCopy(true, false), 672, 486, ButtonType.NEXT);
        b.setShown(false);
        this.getButtons().add(b);

    }

    protected void loadButtons()
            throws SlickException {

        String dirPath = "assets/menu/submenu/", hover = "hover_", file;

        Image nor, hov;
        MenuButton b;

        if (this.isShowingCancelOK()) {

            file = "ok.png";
            nor = ImageLoader.getLoadedImage(dirPath + file);
            hov = ImageLoader.getLoadedImage(dirPath + hover + file);
            b = new MenuButton(nor, hov, 250, 486, ButtonType.OK);
            this.getButtons().add(b);

            file = "cancel.png";
            nor = ImageLoader.getLoadedImage(dirPath + file);
            hov = ImageLoader.getLoadedImage(dirPath + hover + file);
            b = new MenuButton(nor, hov, 400, 486, ButtonType.CANCEL);
            this.getButtons().add(b);

        }

    }

    /** Update the game state for a frame.
     * @param input The input object
     * @param mousepress Indicates if the LEFT mouse button has been pressed.
     * @param delta Time passed since last frame (milliseconds).
     */
    public void update(Input input, boolean mousepress, int delta)
            throws SlickException {

        if (this.isShowing()) {

            if (this.isOpening()) {
                if (this.getDisplayAnimation().isStopped()) {
                    this.setOpening(false);
                }
            } else if (this.isClosing()) {
                if (this.getDisplayAnimation().isStopped()) {
                    this.hide();
                }
            } else {

                boolean escape = input.isKeyDown(Input.KEY_ESCAPE);

                if (escape) {
                    this.close();
                }

                float mousex = input.getMouseX();
                float mousey = input.getMouseY();
                boolean mousedown = input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON);

                this.setClick(mousepress);

                this.setMenuState(this.isAnyButtonPressed(mousex, mousey));

                this.getTabs().get(this.getCurrentTab()).update(input, delta);

                if (this.getMenuState() == ButtonType.BACK) {
                    this.goBack();
                } else if (this.getMenuState() == ButtonType.NEXT) {
                    this.goNext();
                }

                // back button
                this.getButtons().get(0).setShown(this.isShowingBack());
                // next button
                this.getButtons().get(1).setShown(this.isShowingNext());

                for (MenuButton b : this.getButtons()) {
                    b.update(mousex, mousey, mousedown, delta);
                }

                // ok and cancel buttons
                if (this.getMenuState() == ButtonType.OK) {
                    this.saveChanges();
                    this.close();
                } else if (this.getMenuState() == ButtonType.CANCEL) {
                    this.close();
                }

            }

        }

    }

    /** Render the menu
     * @param g The Slick graphics object, used for drawing.
     */
    public void render(Graphics g)
            throws SlickException {

        if (this.isShowing()) {

            this.getDisplayAnimation().draw();

            if (!this.isOpening() && !this.isClosing()) {

                // render title
                String text = this.getTitle();
                g.setFont(FontLoader.getFontTitle());
                g.setColor(FontLoader.getTitleColor());
                int width = g.getFont().getWidth(text);
                int x = (RPG.getScreenWidth() - width) / 2;
                g.drawString(text, x, TITLE_TOP);

                // render back to Main Menu
                g.setFont(FontLoader.getFontSize12());
                g.setColor(Color.white);
                width = g.getFont().getWidth(ESCAPE);
                x = (RPG.getScreenWidth() - width) / 2;
                g.drawString(ESCAPE, x, RPG.getScreenHeight() - ESCAPE_TOP);

                this.getTabs().get(this.getCurrentTab()).render(g);

                for (MenuButton b : this.getButtons()) {
                    b.render(g);
                }

            }

        }

    }

    /** Checks if any of the buttons were pressed.
     * @param x The x coordinate of the mouse pointer.
     * @param y The y coordinate of the mouse pointer.
     */
    private MenuButton.ButtonType isAnyButtonPressed(float x, float y) {
        if (this.isClicked()) {
            for (MenuButton b : this.getButtons()) {
                if (b.isShown() && b.isOnButton(x, y)) {
                    return b.getType();
                }
            }
        }
        return MenuButton.ButtonType.NONE;
    }

    public MenuButton.ButtonType getMenuState() {
        return this.menuState;
    }

    public void setMenuState(MenuButton.ButtonType menuState) {
        this.menuState = menuState;
    }

    private boolean isClicked() {
        return this.click;
    }

    private void setClick(boolean click) {
        this.click = click;
    }

    protected boolean isOpening() {
        return this.opening;
    }

    private void setOpening(boolean opening) {
        this.opening = opening;
    }

    protected boolean isClosing() {
        return this.closing;
    }

    private void setClosing(boolean closing) {
        this.closing = closing;
    }

    /** Open up the submenu (animations used)
     *
     */
    public void open() {
        this.setCurrentTab(0);
        this.setOpening(true);
        this.setClosing(false);
        this.setDisplayAnimation(ImageLoader.getSubMenuOpen());
        this.setShowing(true);
        this.getDisplayAnimation().restart();
        this.resetTabs();
    }

    /** Close up the submenu (animations used)
     *
     */
    public void close() {
        this.setOpening(false);
        this.setClosing(true);
        this.setDisplayAnimation(ImageLoader.getSubMenuClose());
        this.getDisplayAnimation().restart();
    }

    private void hide() {
        this.setShowing(false);
        this.getMenu().setMenuState(MenuButton.ButtonType.NONE);
    }

    private Animation getDisplayAnimation() {
        return this.disp;
    }

    private void setDisplayAnimation(Animation disp) {
        this.disp = disp;
    }

    protected boolean isShowing() {
        return this.showing;
    }

    private void setShowing(boolean showing) {
        this.showing = showing;
    }

    protected Menu getMenu() {
        return menu;
    }

    private void setMenu(Menu menu) {
        this.menu = menu;
    }

    public String getTitle() {
        return title;
    }

    private void setTitle(String title) {
        this.title = title;
    }

    protected ArrayList<MenuTab> getTabs() {
        return this.tabs;
    }

    private void setTabs(ArrayList<MenuTab> tabs) {
        this.tabs = tabs;
    }

    public int getCurrentTab() {
        return this.currentTab;
    }

    private void setCurrentTab(int currentTab) {
        this.currentTab = currentTab;
    }

    private boolean isShowingNext() {
        return (this.getCurrentTab() < this.getTabs().size() - 1);
    }

    private boolean isShowingBack() {
        return (this.getCurrentTab() > 0);
    }

    private void goBack() {
        if (this.getCurrentTab() > 0) {
            this.setCurrentTab(this.getCurrentTab() - 1);
        }
    }

    private void goNext() {
        if (this.getCurrentTab() < this.getTabs().size() - 1) {
            this.setCurrentTab(this.getCurrentTab() + 1);
        }
    }

    private boolean isShowingCancelOK() {
        return showingCancelOK;
    }

    private void setShowingCancelOK(boolean showingCancelOK) {
        this.showingCancelOK = showingCancelOK;
    }

    private void saveChanges() {

        for (MenuTab t : this.getTabs()) {
            t.saveObjectValues();
        }

    }

    private void resetTabs() {

        for (MenuTab t : this.getTabs()) {
            t.resetTab();
        }

    }

    protected void addTab(MenuTab tab) {
        this.getTabs().add(tab);
    }

    protected ArrayList<MenuButton> getButtons() {
        return buttons;
    }

    protected void setButtons(ArrayList<MenuButton> buttons) {
        this.buttons = buttons;
    }
}
